package beer.zivelin.awesome.walawala.mobile.service;

import com.github.houbb.pinyin.constant.enums.PinyinStyleEnum;
import com.github.houbb.pinyin.util.PinyinHelper;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

/***
 * @author zhaolin
 * @description 根据汉字生成拼音，依赖Guava+com.github.houbb-pinyin库
 * @date 2022-05-16 19:04:25
 **/
public class PinyinAnalyzer {
    static final char ORIGIN_V = 'ü';
    static final char TARGET_V = 'v';

    /**
     * 采用常见音调，不做多音字识别
     * @param str
     * @return
     */
    public static Set<String> toNormalPinyin(String str){
        Set<String> result = new HashSet<>();
        String _fullPinyin = PinyinHelper.toPinyin(str, PinyinStyleEnum.NORMAL);
        StringBuilder fullPinyinBuf = new StringBuilder();
        for (char c : _fullPinyin.toCharArray()) {
            if (c == ORIGIN_V) {
                c = TARGET_V;
            }
            if(isAsciiLetter(c)){
                fullPinyinBuf.append(c);
            }
        }
        result.add(fullPinyinBuf.toString());

        StringBuilder sentenceBuf = new StringBuilder();
        char[] chars = str.toCharArray();
        boolean lastIsAscii = false;
        for (int i = 0; i < chars.length; i++) {
            char c = chars[i];
            if (c == ORIGIN_V) {
                c = TARGET_V;
            }
            if(i == 0){
                sentenceBuf.append(c);
                lastIsAscii = isAsciiLetter(c);
            }else{
                boolean isAscii = isAsciiLetter(c);
                if(lastIsAscii && isAscii){
                    //skip
                }else {
                    sentenceBuf.append(c);
                }
                lastIsAscii = isAscii;
            }
        }
        String _shortPinyin = PinyinHelper.toPinyin(sentenceBuf.toString(), PinyinStyleEnum.FIRST_LETTER);
        StringBuilder shortPinyinBuf = new StringBuilder();
        for (char c : _shortPinyin.toCharArray()) {
            if(isAsciiLetter(c)){
                shortPinyinBuf.append(c);
            }
        }
        result.add(shortPinyinBuf.toString());

        return result;
    }

    /**
     * 含全拼+字首
     *
     * @param str
     * @return
     */
    public static Set<List<String>> toPinyin(String str) {
        return Sets.union(toFullPinyin(str), toShortPinyin(str));
    }

    /**
     * 全拼，如 我=wo
     *
     * @param str
     * @return
     */
    public static Set<List<String>> toFullPinyin(String str) {
        List<Set<String>> pinyinList = new LinkedList<>();
        List<Set<String>> firstLetterPinyinList = new LinkedList<>();
        for (char c : str.toCharArray()) {
            Set<String> s1 = producePinyin(c, PinyinStyleEnum.NORMAL);
            if (s1 != null && s1.size() > 0) {
                pinyinList.add(s1);
            }

            Set<String> s2 = producePinyin(c, PinyinStyleEnum.FIRST_LETTER);
            if (s2 != null && s2.size() > 0) {
                firstLetterPinyinList.add(s2);
            }
        }

        return Sets.union(Sets.cartesianProduct(pinyinList), Sets.cartesianProduct(firstLetterPinyinList));
    }

    /**
     * 字首，如 我=w
     *
     * @param str
     * @return
     */
    public static Set<List<String>> toShortPinyin(String str) {
        List<Set<String>> firstLetterPinyinList = new LinkedList<>();
        boolean isAsciiLetter = false;//是否是A-Za-z字母
        for (char c : str.toCharArray()) {
            if (isAsciiLetter(c)) {
                if (isAsciiLetter) {
                    continue;
                } else {
                    isAsciiLetter = true;
                    firstLetterPinyinList.add(Sets.newHashSet(Character.toString(c)));
                }
            } else {
                isAsciiLetter = false;
                Set<String> s2 = producePinyin(c, PinyinStyleEnum.FIRST_LETTER);
                if (s2 != null && s2.size() > 0) {
                    firstLetterPinyinList.add(s2);
                }
            }
        }

        return Sets.cartesianProduct(firstLetterPinyinList);
    }

    //每个字的拼音，考虑到多音字，所以放入Set
    static Set<String> producePinyin(char chinese, PinyinStyleEnum style) {
        Set<String> s = new HashSet<>();

        List<String> pinyinList = PinyinHelper.toPinyinList(chinese, style);
        if (pinyinList != null) {
            s.addAll(onlyPinyin(pinyinList));
        }
        return s;
    }

    static List<String> onlyPinyin(List<String> src) {
        List<String> dest = new LinkedList<>();
        for (String pinyin : src) {
            String temp = "";
            for (char c : pinyin.toCharArray()) {
                if (!isAsciiLetter(c)) {
                    temp = null;
                    break;
                }
                if (c == ORIGIN_V) {
                    c = TARGET_V;
                }
                temp += c;
            }
            if (temp != null) {
                dest.add(temp);
            }
        }
        return dest;
    }

    private static boolean isAsciiLetter(char c) {
        return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9');
    }
}
